---! 映射表
local clients_map = {}

-------------------------------------------------------------------------------
---! 对外接口
-------------------------------------------------------------------------------
LOGIN_D = {}

---! 登录
function LOGIN_D:login(loginTime, clientAddr, clientId, loginInfo)
    local userId = loginInfo.PlayerID
    if not userId then
        spdlog.warn("logind", string.format("member[PlayerID] type error, data : %s", loginInfo));
        return
    end

    spdlog.debug("logind", string.format("client [%s] from [%s] try do login user [%s].", clientId, clientAddr, userId))

    ---! 查找用户对象
    local userOb = USER_D:find_user(userId)
    if not userOb then
        ---! 对象尚未加载，需要做防重入处理，避免多次加载对象
        if USER_D:is_loading(userId) then
            spdlog.debug("logind", string.format("user [%s] is loading....", userId))
            ---! 通知客户端下线
            LOGIN_D:kickout(clientAddr, clientId, 1001)
            return
        end

        ---! 开始加载对象
        userOb = USER_D:load_user(userId)
        if not userOb then
            spdlog.debug("logind", string.format("user [%s] load failed.", userId))
            ---! 通知客户端下线
            LOGIN_D:kickout(clientAddr, clientId, 1002)
            return
        end

        ---! 设置登录信息
        userOb:set_temp("clientAddr",   clientAddr)
        userOb:set_temp("clientId",     clientId)
        userOb:set_temp("loginInfo",    loginInfo)
        userOb:set_temp("loginTime",    loginTime)

        ---! 初始玩家数据
        USER_D:init_user(userOb)
        ---! 更新角色数据
        userOb:update_data()
        ---! 安排进入游戏
        USER_D:enter_world(userOb)

        ---! 记录登录日志
        LOG_D:write_login_log("login", 1, userOb)
    else
        local last_client_id = userOb:query_temp("clientId")
        if last_client_id and last_client_id ~= clientId then
            spdlog.debug("logind", string.format("user [%s] disconnected for a long time.", userId))
            ---! 断开之前连接
            USER_D:disconnect(userOb, 2)
        end

        ---! 设置登录信息
        userOb:set_temp("clientAddr",   clientAddr)
        userOb:set_temp("clientId",     clientId)
        userOb:set_temp("loginInfo",    loginInfo)
        userOb:set_temp("loginTime",    loginTime)

        ---! 重新进入游戏
        USER_D:reconnect(userOb)

        ---! 记录重登日志
        LOG_D:write_login_log("reconnect", 1, userOb)
    end

    ---! 记录登录成功的玩家对象
    clients_map[clientId] = userOb

    ---! 发送大厅信息
    USER_D:send_hall_info(userOb)
    ---! 发送道具信息
    ITEM_D:send_item_info(userOb)
    ---! 发送技能信息
    SKILL_D:send_skill_info(userOb)
    ---! 发送装备信息
    EQUIP_D:send_equip_info(userOb)
    ---! 发送翅膀信息
    WING_D:send_wing_info(userOb)
    ---! 发送神器信息
    ARTIFACT_D:send_artifact_info(userOb)
    ---! 发送伙伴信息
    PARTNER_D:send_partner_info(userOb)
    ---! 发送福利信息
    WELFARE_D:send_welfare_info(userOb)
    ---! 发送副本信息
    ----todo: 暂未开放，先屏蔽
    -- DUNGEON_D:send_dungeon_info(userOb)

    ---! 记录当前指令处理时间
    userOb:set_temp("command_time", os.time())
end

---! 断开
function LOGIN_D:disconnect(user_ob)
    local clientId = user_ob:query_temp("clientId")
    if not clientId then
        return
    end

    ---! 清理玩家登录信息
    user_ob:delete_temp("clientId")
    user_ob:delete_temp("clientAddr")
    user_ob:delete_temp("loginTime")

    ---! 清理关联映射
    clients_map[clientId] = nil
end

---! 登出
function LOGIN_D:logout(user_ob)
    local client_id = user_ob:query_temp("clientId")
    if not client_id then
        return
    end

    ---! 断开当前连接
    USER_D:disconnect(user_ob, 1)
end

---! 踢出
function LOGIN_D:kickout(clientAddr, clientId, reason)
    local result = {}
    result.reason = reason or 1000
    USER_D:send_packet(clientAddr, clientId, "MSGS2CLeaveGame", result)
    -- USER_D:send_packet2(clientAddr, clientId, "MSG_DISCONNECT", { MsgType = "MSGS2CLeaveGame", MsgValue = result, })
end

---! 查找
function LOGIN_D:find_user(clientId)
    return clients_map[clientId]
end

function LOGIN_D:find_all_user()
    return clients_map
end
